home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 October / EnigmA AMIGA RUN 01 (1995)(G.R. Edizioni)(IT)[!][issue 1995-10][Aminet 7].iso / Aminet / gfx / show / svoUtah22.lha / svoUtahRLE / source / URT / lib / rle_putrow.c < prev    next >
C/C++ Source or Header  |  1991-08-09  |  15KB  |  647 lines

  1. /*
  2.  * This software is copyrighted as noted below.  It may be freely copied,
  3.  * modified, and redistributed, provided that the copyright notice is 
  4.  * preserved on all copies.
  5.  * 
  6.  * There is no warranty or other guarantee of fitness for this software,
  7.  * it is provided solely "as is".  Bug reports or fixes may be sent
  8.  * to the author, who may or may not act on them as he desires.
  9.  *
  10.  * You may not include this software in a program or other software product
  11.  * without supplying the source, or without informing the end-user that the 
  12.  * source is available for no extra charge.
  13.  *
  14.  * If you modify this software, you should include a notice giving the
  15.  * name of the person performing the modification, the date of modification,
  16.  * and the reason for such modification.
  17.  *
  18.  *  Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
  19.  *  to have all "void" functions so declared.
  20.  */
  21. /* 
  22.  * rle_putrow.c - Save a row of the fb to a file.
  23.  * 
  24.  * Author:    Spencer W. Thomas
  25.  *         Computer Science Dept.
  26.  *         University of Utah
  27.  * Date:    1 April 1981
  28.  * Copyright (c) 1981,1986 Spencer W. Thomas
  29.  *
  30.  * $Id: rle_putrow.c,v 3.0.1.1 90/11/27 14:54:37 spencer Exp $
  31.  */
  32.  
  33. #include "stdio.h"
  34. #include "rle_put.h"
  35. #include "rle.h"
  36. #ifdef USE_STDLIB_H
  37. #include <stdlib.h>
  38. #else
  39.  
  40. #ifndef VOID_STAR
  41. extern char * malloc();
  42. #else
  43. extern void *malloc();
  44. #endif
  45. extern void free();
  46.  
  47. #endif /* USE_STDLIB_H */
  48.  
  49. static int findruns();
  50.  
  51. #define FASTRUNS        /* Faster run finding */
  52. #ifdef vax
  53. #define LOCC            /* Use vax instructions for more speed */
  54. #endif
  55.  
  56. #define    FALSE    0
  57. #define    TRUE    1
  58.  
  59. /*****************************************************************
  60.  * TAG( rle_putrow )
  61.  * Write a scanline to the output file.
  62.  * 
  63.  * Inputs:
  64.  *    rows:        Pointer to vector of pointers to
  65.  *            rle_pixel arrays containing the pixel information.
  66.  *            If NULL, rowlen scanlines are skipped.
  67.  *    rowlen:        The number of pixels in the scanline, or the
  68.  *            number of scanlines to skip (see above).
  69.  * Outputs:
  70.  *     Run length encoded information is written to the_hdr.rle_file.
  71.  * Assumptions:
  72.  *     I'm sure there are lots of assumptions in here.
  73.  * Algorithm:
  74.  *     [read the code :-]
  75.  */
  76.  
  77. void
  78. rle_putrow(rows, rowlen, the_hdr)
  79. register rle_pixel *rows[];
  80. int rowlen;
  81. register rle_hdr * the_hdr;
  82. {
  83.     register int i, j;
  84.     int nrun;
  85.     register rle_pixel *row;
  86.     int mask;
  87.     char bits[256];
  88.     short   state,
  89.         dstart,
  90.             dend,
  91.         rstart = 0,
  92.         runval = 0;            /* shut up lint */
  93.  
  94.     if (rows == NULL)
  95.     {
  96.     the_hdr->priv.put.nblank += rowlen;
  97.     return;
  98.     }
  99.     /* 
  100.      * If not done already, allocate space to remember runs of
  101.      * non-background color.  A run of bg color must be at least 2
  102.      * bytes long to count, so there can be at most rowlen/3 of them.
  103.      */
  104.     if ( the_hdr->priv.put.brun == NULL )
  105.     {
  106.     the_hdr->priv.put.brun =
  107.         (short (*)[2])malloc(
  108.         (unsigned)((rowlen/3 + 1) * 2 * sizeof(short)) );
  109.     if ( the_hdr->priv.put.brun == NULL )
  110.     {
  111.         fprintf( stderr, "Malloc failed in rle_putrow\n" );
  112.         exit(1);
  113.     }
  114.     }
  115.     /* Unpack bitmask in the_hdr struct */
  116.     for ( i=0; i < the_hdr->ncolors; i++ )
  117.     bits[i] = RLE_BIT( *the_hdr, i );
  118.     bits[255] = RLE_BIT( *the_hdr, -1 );
  119.  
  120.     /* 
  121.      * If saving only non-background pixels, find runs of them.  Note
  122.      * that the alpha channel is considered to be background iff it is
  123.      * zero.
  124.      */
  125. #ifdef    FASTRUNS
  126.     if ( the_hdr->background )
  127.     {
  128.     /* 
  129.      * Find runs in each color individually, merging them as we go.
  130.      */
  131.     nrun = 0;        /* start out with no runs */
  132.     /* Alpha channel first */
  133.     if ( the_hdr->alpha )
  134.         nrun = findruns( rows[-1], rowlen, 0, nrun,
  135.                 the_hdr->priv.put.brun );
  136.     /* Now the color channels */
  137.     for ( i = 0; i < the_hdr->ncolors; i++ )
  138.         if ( bits[i] )
  139.         nrun = findruns( rows[i], rowlen, the_hdr->bg_color[i],
  140.                  nrun, the_hdr->priv.put.brun );
  141.     }
  142.     else
  143.     {
  144.     the_hdr->priv.put.brun[0][0] = 0;
  145.     the_hdr->priv.put.brun[0][1] = rowlen-1;
  146.     nrun = 1;
  147.     }
  148. #else                /* FASTRUNS */
  149.     if (the_hdr->background)    /* find non-background runs */
  150.     {
  151.     j = 0;
  152.     for (i=0; i<rowlen; i++)
  153.         if (!same_color( i, rows, the_hdr->bg_color,
  154.                  the_hdr->ncolors, bits ) ||
  155.         (the_hdr->alpha && rows[-1][i] != 0))
  156.         {
  157.         if (j > 0 && i - the_hdr->priv.put.brun[j-1][1] <= 4)
  158.             j--;
  159.         else
  160.             the_hdr->priv.put.brun[j][0] = i; /* start of run */
  161.         for ( i++;
  162.               i < rowlen && 
  163.             ( !same_color( i, rows, the_hdr->bg_color,
  164.                      the_hdr->ncolors, bits ) ||
  165.               (the_hdr->alpha && rows[-1][i] != 0) );
  166.               i++)
  167.             ;            /* find the end of this run */
  168.         the_hdr->priv.put.brun[j][1] = i-1;    /* last in run */
  169.         j++;
  170.         }
  171.     nrun = j;
  172.     }
  173.     else
  174.     {
  175.     the_hdr->priv.put.brun[0][0] = 0;
  176.     the_hdr->priv.put.brun[0][1] = rowlen-1;
  177.     nrun = 1;
  178.     }
  179. #endif                /* FASTRUNS */
  180.     if (nrun > 0)
  181.     {
  182.     if (the_hdr->priv.put.nblank > 0)
  183.     {
  184.         SkipBlankLines(the_hdr->priv.put.nblank);
  185.         the_hdr->priv.put.nblank = 0;
  186.     }
  187.     for ( mask = (the_hdr->alpha ? -1 : 0);
  188.           mask < the_hdr->ncolors;
  189.           mask++)            /* do all colors */
  190.     {
  191.         if ( ! bits[mask & 0xff] )
  192.         {
  193.         continue;
  194.         }
  195.         row = rows[mask];
  196.         SetColor(mask);
  197.         if (the_hdr->priv.put.brun[0][0] > 0)
  198.         {
  199.         SkipPixels(the_hdr->priv.put.brun[0][0], FALSE, FALSE);
  200.         }
  201.         for (j=0; j<nrun; j++)
  202.         {
  203.         state = DATA;
  204.         dstart = the_hdr->priv.put.brun[j][0];
  205.         dend = the_hdr->priv.put.brun[j][1];
  206.         for (i=dstart; i<=dend; i++)
  207.         {
  208.             switch(state)
  209.             {
  210.             case DATA:
  211.             if (i > dstart && runval == row[i])
  212.             {
  213.                 state = RUN2;    /* 2 in a row, may be a run */
  214.             }
  215.             else
  216.             {
  217.                 runval = row[i];    /* maybe a run starts here? */
  218.                 rstart = i;
  219.             }
  220.             break;
  221.         
  222.             case RUN2:
  223.             if (runval == row[i])
  224.             {
  225.                 state  = RUN3;    /* 3 in a row may be a run */
  226.             }
  227.             else
  228.             {
  229.                 state = DATA;    /* Nope, back to data */
  230.                 runval = row[i];    /* but maybe a new run here? */
  231.                 rstart = i;
  232.             }
  233.             break;
  234.  
  235.             case RUN3:
  236.             if (runval == row[i])    /* 3 in a row is a run */
  237.             {
  238.                 state = INRUN;
  239.                 putdata(row + dstart, rstart - dstart);
  240. #ifdef FASTRUNS
  241. #ifdef LOCC
  242.                 /* Shortcut to find end of run! */
  243.                 i = dend - skpc( (char *)row + i, dend + 1 - i,
  244.                          runval );
  245. #else
  246.                 while ( row[++i] == runval && i <= dend)
  247.                 ; /* not quite so good, but not bad */
  248.                 i--;
  249. #endif /* LOCC */
  250. #endif /* FASTRUNS */
  251.             }
  252.             else
  253.             {
  254.                 state = DATA;        /* not a run, */
  255.                 runval = row[i];    /* but may this starts one */
  256.                 rstart = i;
  257.             }
  258.             break;
  259.         
  260.             case INRUN:
  261.             if (runval != row[i])    /* if run out */
  262.             {
  263.                 state = DATA;
  264.                 putrun(runval, i - rstart, FALSE);
  265.                 runval = row[i];    /* who knows, might be more */
  266.                 rstart = i;
  267.                 dstart = i;    /* starting a new 'data' run */
  268.             }
  269.             break;
  270.             }
  271.         }
  272.         if (state == INRUN)
  273.             putrun(runval, i - rstart, TRUE);    /* last bit */
  274.         else
  275.             putdata(row + dstart, i - dstart);
  276.  
  277.         if (j < nrun-1)
  278.             SkipPixels(
  279.                 the_hdr->priv.put.brun[j+1][0] - dend - 1,
  280.                 FALSE, state == INRUN);
  281.         else
  282.         {
  283.             if (rowlen - dend > 0)
  284.             SkipPixels(
  285.                 rowlen - dend - 1,
  286.                 TRUE, state == INRUN);
  287.         }
  288.         }
  289.  
  290.         if ( mask != the_hdr->ncolors - 1 )
  291.         NewScanLine(FALSE);
  292.     }
  293.     }
  294.  
  295.     /* Increment to next scanline */
  296.     the_hdr->priv.put.nblank++;
  297.  
  298.     /* flush every scanline */
  299.     fflush( the_hdr->rle_file );
  300. }
  301.  
  302.  
  303. /*****************************************************************
  304.  * TAG( rle_skiprow )
  305.  * 
  306.  * Skip rows in RLE file.
  307.  * Inputs:
  308.  *     the_hdr:        Header struct for RLE output file.
  309.  *      nrow:            Number of rows to skip.
  310.  * Outputs:
  311.  *     Increments the nblank field in the the_hdr struct, so that a Skiplines
  312.  *      code will be output the next time rle_putrow or rle_putraw is called.
  313.  * Assumptions:
  314.  *     Only effective when called between rle_putrow or rle_putraw calls (or
  315.  *      some other routine that follows the same conventions.
  316.  * Algorithm:
  317.  *    [None]
  318.  */
  319. void
  320. rle_skiprow( the_hdr, nrow )
  321. rle_hdr *the_hdr;
  322. int nrow;
  323. {
  324.     the_hdr->priv.put.nblank += nrow;
  325. }
  326.  
  327.  
  328. /*****************************************************************
  329.  * TAG( rle_put_init )
  330.  * 
  331.  * Initialize the header structure for writing scanlines. 
  332.  * Inputs:
  333.  *    [None]
  334.  * Outputs:
  335.  *     the_hdr:    Private portions initialized for output.
  336.  * Assumptions:
  337.  *    [None]
  338.  * Algorithm:
  339.  *    [None]
  340.  */
  341. void
  342. rle_put_init( the_hdr )
  343. register rle_hdr *the_hdr;
  344. {
  345.     the_hdr->dispatch = RUN_DISPATCH;
  346.     the_hdr->priv.put.nblank = 0;    /* Reinit static vars */
  347.     /* Would like to be able to free previously allocated storage,
  348.      * but can't count on a non-NULL value being a valid pointer.
  349.      */
  350.     the_hdr->priv.put.brun = NULL;
  351.     the_hdr->priv.put.fileptr = 0;
  352.  
  353.     /* Only save alpha if alpha AND alpha channel bit are set. */
  354.     if ( the_hdr->alpha )
  355.     the_hdr->alpha = (RLE_BIT( *the_hdr, -1 ) != 0);
  356.     else
  357.     RLE_CLR_BIT( *the_hdr, -1 );
  358. }
  359.  
  360. /*****************************************************************
  361.  * TAG( rle_put_setup )
  362.  * 
  363.  * Initialize for writing RLE, and write header to output file.
  364.  * Inputs:
  365.  *     the_hdr:    Describes output image.
  366.  * Outputs:
  367.  *     the_hdr:    Initialized.
  368.  * Assumptions:
  369.  *    Lots of them.
  370.  * Algorithm:
  371.  *    [None]
  372.  */
  373. void
  374. rle_put_setup( the_hdr )
  375. register rle_hdr * the_hdr;
  376. {
  377.     rle_put_init( the_hdr );
  378.     Setup();
  379. }
  380.  
  381. /*ARGSUSED*/
  382. void
  383. DefaultBlockHook(the_hdr)
  384. rle_hdr * the_hdr;
  385. {
  386.                         /* Do nothing */
  387. }
  388.  
  389. /*****************************************************************
  390.  * TAG( rle_puteof )
  391.  * Write an EOF code into the output file.
  392.  */
  393. void
  394. rle_puteof( the_hdr )
  395. register rle_hdr * the_hdr;
  396. {
  397.     /* Don't puteof twice. */
  398.     if ( the_hdr->dispatch == NO_DISPATCH )
  399.     return;
  400.     PutEof();
  401.     fflush( the_hdr->rle_file );
  402.     /* Free storage allocated by rle_put_init. */
  403.     if ( the_hdr->priv.put.brun != NULL )
  404.     {
  405.     free( the_hdr->priv.put.brun );
  406.     the_hdr->priv.put.brun = NULL;
  407.     }
  408.     /* Signal that puteof has been called. */
  409.     the_hdr->dispatch = NO_DISPATCH;
  410. }
  411.  
  412. #ifndef FASTRUNS
  413. /*****************************************************************
  414.  * TAG( same_color )
  415.  * 
  416.  * Determine if the color at the given index position in the scan rows
  417.  * is the same as the background color.
  418.  * Inputs:
  419.  *     index:        Index to the pixel position in each row.
  420.  *    rows:        array of pointers to the scanlines
  421.  *    bg_color:   the background color
  422.  *    ncolors:    number of color elements/pixel
  423.  * Outputs:
  424.  *     TRUE if the color at row[*][i] is the same as bg_color[*].
  425.  * Assumptions:
  426.  *    [None]
  427.  * Algorithm:
  428.  *    [None]
  429.  */
  430. static int
  431. same_color( index, rows, bg_color, ncolors, bits )
  432. register rle_pixel *rows[];
  433. register int bg_color[];
  434. char *bits;
  435. {
  436.     register int i;
  437.  
  438.     for ( i = 0; i < ncolors; i++, bits++ )
  439.     if ( *bits &&
  440.          rows[i][index] != bg_color[i] )
  441.         return 0;
  442.     return 1;                /* all the same */
  443. }
  444. #endif /* !FASTRUNS */
  445.  
  446. /*****************************************************************
  447.  * TAG( findruns )
  448.  * 
  449.  * Find runs not a given color in the row.
  450.  * Inputs:
  451.  *     row:        Row of pixel values
  452.  *    rowlen:        Number of pixels in the row.
  453.  *    color:        Color to compare against.
  454.  *    nrun:        Number of runs already found (in different colors).
  455.  *    brun:        Runs found in other color channels already.
  456.  * Outputs:
  457.  *     brun:        Modified to reflect merging of runs in this color.
  458.  *    Returns number of runs in brun.
  459.  * Assumptions:
  460.  *
  461.  * Algorithm:
  462.  *     Search for occurences of pixels not of the given color outside the
  463.  *    runs already found.  When some are found, add a new run or extend
  464.  *    an existing one.  Adjacent runs with fewer than two pixels intervening
  465.  *    are merged.
  466.  */
  467. static int
  468. findruns( row, rowlen, color, nrun, brun )
  469. register rle_pixel *row;
  470. int rowlen, color, nrun;
  471. short (*brun)[2];
  472. {
  473.     int i = 0, lower, upper;
  474.     register int s, j;
  475.  
  476. #ifdef DEBUG
  477.     fprintf( stderr, "findruns( " );
  478.     for ( s = 0; s < rowlen; s++ )
  479.     fprintf( stderr, "%2x.%s", row[s], (s % 20 == 19) ? "\n\t" : "" );
  480.     if ( s % 20 != 0 )
  481.     fprintf( stderr, "\n\t" );
  482.     fprintf( stderr, "%d, %d, %d, \n\t", rowlen, color, nrun );
  483.     for ( j = 0; j < nrun; j++ )
  484.     fprintf( stderr, "(%3d,%3d) %s", brun[j][0], brun[j][1],
  485.         (j % 6 == 5) ? "\n\t" : "" );
  486.     fprintf( stderr, ")\n" );
  487. #endif
  488.  
  489.     while ( i <= nrun )
  490.     {
  491.     /* Assert: 0 <= i <= rowlen
  492.      * brun[i] is the run following the "blank" space being
  493.      * searched.  If i == rowlen, search after brun[i-1].
  494.      */
  495.  
  496.     /* get lower and upper bounds of search */
  497.  
  498.     if ( i == 0 )
  499.         lower = 0;
  500.     else
  501.         lower = brun[i-1][1] + 1;
  502.  
  503.     if ( i == nrun )
  504.         upper = rowlen - 1;
  505.     else
  506.         upper = brun[i][0] - 1;
  507.  
  508. #ifdef DEBUG
  509.     fprintf( stderr, "Searching before run %d from %d to %d\n",
  510.         i, lower, upper );
  511. #endif
  512.     /* Search for beginning of run != color */
  513. #if  defined(LOCC)&defined(vax)
  514.     s = upper - skpc( (char *)row + lower, upper - lower + 1, color ) + 1;
  515. #else
  516.     for ( s = lower; s <= upper; s++ )
  517.         if ( row[s] != color )
  518.         break;
  519. #endif
  520.  
  521.     if ( s <= upper )    /* found a new run? */
  522.     {
  523.         if ( s > lower + 1 || i == 0 ) /* disjoint from preceding run? */
  524.         {
  525. #ifdef DEBUG
  526.         fprintf( stderr, "Found new run starting at %d\n", s );
  527. #endif
  528.         /* Shift following runs up */
  529.         for ( j = nrun; j > i; j-- )
  530.         {
  531.             brun[j][0] = brun[j-1][0];
  532.             brun[j][1] = brun[j-1][1];
  533.         }
  534.         brun[i][0] = s;
  535.         nrun++;
  536.         }
  537.         else
  538.         {
  539.         i--;        /* just add to preceding run */
  540. #ifdef DEBUG
  541.         fprintf( stderr, "Adding to previous run\n" );
  542. #endif
  543.         }
  544.  
  545. #if defined(LOCC)&defined(vax)
  546.         s = upper - locc( (char *)row + s, upper - s + 1, color ) + 1;
  547. #else
  548.         for ( ; s <= upper; s++ )
  549.         if ( row[s] == color )
  550.             break;
  551. #endif
  552.         brun[i][1] = s - 1;
  553.  
  554. #ifdef DEBUG
  555.         fprintf( stderr, "Ends at %d", s - 1 );
  556. #endif
  557.         if ( s >= upper && i < nrun - 1 ) /* merge with following run */
  558.         {
  559.         brun[i][1] = brun[i+1][1];
  560.         /* move following runs back down */
  561.         for ( j = i + 2; j < nrun; j++ )
  562.         {
  563.             brun[j-1][0] = brun[j][0];
  564.             brun[j-1][1] = brun[j][1];
  565.         }
  566.         nrun--;
  567. #ifdef DEBUG
  568.         fprintf( stderr, ", add to next run" );
  569. #endif
  570.         }
  571. #ifdef DEBUG
  572.         putc( '\n', stderr );
  573. #endif
  574.     }
  575.     
  576.     /* Search in next space */
  577.     i++;
  578.     }
  579.  
  580.     return nrun;
  581. }
  582.  
  583.  
  584. /*****************************************************************
  585.  * TAG( rgb_to_bw )
  586.  * 
  587.  * Perform the NTSC Y transform on RGB data to get B&W data.
  588.  * Inputs:
  589.  *     red_row, green_row, blue_row:    Given RGB pixel data.
  590.  *    rowlen:        Number of pixels in the rows.
  591.  * Outputs:
  592.  *     bw_row:        Output B&W data.  May coincide with one of the
  593.  *            inputs.
  594.  * Assumptions:
  595.  *    [None]
  596.  * Algorithm:
  597.  *     BW = .30*R + .59*G + .11*B
  598.  */
  599. void
  600. rgb_to_bw( red_row, green_row, blue_row, bw_row, rowlen )
  601. rle_pixel *red_row;
  602. rle_pixel *green_row;
  603. rle_pixel *blue_row;
  604. rle_pixel *bw_row;
  605. int rowlen;
  606. {
  607.     register int x, bw;
  608.  
  609.     for (x=0; x<rowlen; x++)
  610.     {
  611.     /* 68000 won't store float > 127 into byte? */
  612.     /* HP compiler blows it */
  613.     bw = .30*red_row[x] + .59*green_row[x] + .11*blue_row[x];
  614.     bw_row[x] = bw;
  615.     }
  616. }
  617.  
  618. #ifdef LOCC
  619. /*ARGSUSED*/
  620. locc( p, l, c )
  621. register char *p;
  622. register int l;
  623. register int c;
  624. {
  625.     asm( "locc    r9,r10,(r11)" );
  626. #ifdef lint
  627.     c = (int) p;        /* why doesn't ARGSUSED work? */
  628.     l = c;
  629.     return l;            /* Needs return value, at least */
  630. #endif
  631. }
  632.  
  633. /*ARGSUSED*/
  634. skpc( p, l, c )
  635. register char *p;
  636. register int l;
  637. register int c;
  638. {
  639.     asm( "skpc r9,r10,(r11)" );
  640. #ifdef lint
  641.     c = (int) p;        /* why doesn't ARGSUSED work? */
  642.     l = c;
  643.     return l;            /* Needs return value, at least */
  644. #endif
  645. }
  646. #endif
  647.